#pragma once

template <typename Key, typename Val>
hIntervalMap<Key, Val>::hIntervalMap()
{
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::~hIntervalMap()
{
	if (_root != NodeTy::_pNil)
		delete _root;
}

template <typename Key, typename Val>
template<typename... Args>
std::pair<typename hIntervalMap<Key, Val>::Iter, bool> hIntervalMap<Key, Val>::emplace(const hInterval<Key>& k, Args... args)
{
	if (_root == NodeTy::_pNil)
		_root = new hIntervalMapNode<Key, Val>(this);

	auto retPr = _root->emplaceCallback(k, args...);
	do 
	{
		if (!retPr.second)
			break;

		retPr.first._pNode->emplaceFixup();
		if (_begNd == NodeTy::_pNil)
		{
			_begNd = retPr.first._pNode;
			_begValNd = retPr.first._pValNode;
			break;
		}

		if (_begNd->_key <= k)
			break;

		_begNd = retPr.first._pNode;
		_begValNd = retPr.first._pValNode;
	} while (0);

	return retPr;
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::Iter hIntervalMap<Key, Val>::erase(const hInterval<Key>& k)
{
	if (_begNd == NodeTy::_pNil)
		return end();

	do 
	{
		if (_begNd->_key != k)
			break;

		_begNd = _begNd->getNextNode();
		if (_begNd == NodeTy::_pNil)
			_begValNd = NULL;
		else
			_begValNd = _begNd->_valList.begin().getRaw();
	} while (0);

	auto [pFixNode, nextIt, num] = _root->eraseCallback(k);
	if (pFixNode)
		pFixNode->eraseFixup();

	return nextIt;
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::Iter hIntervalMap<Key, Val>::erase(Iter it)
{
	if (it == end())
		return end();

	if (_begNd == NodeTy::_pNil)
		return end();

	do
	{
		if (_begNd != it._pNode)
			break;

		if (_begValNd != it._pValNode)
			break;

		if (_begNd->getSize() > 1)
		{
			_begValNd = _begValNd->next(false);
			break;
		}

		_begNd = _begNd->getNextNode();
		if (_begNd == NodeTy::_pNil)
			_begValNd = NULL;
		else
			_begValNd = _begNd->_valList.begin().getRaw();
	} while (0);

	auto [pFixNode, nextIt, num] = it._pNode->eraseCallback(it._pValNode);

	if (pFixNode)
		pFixNode->eraseFixup();

	NodeTy* pNode = it._pNode->_parent;
	while (pNode != NodeTy::_pNil)
	{
		--pNode->_size;
		pNode->calcIntr();
		pNode = pNode->_parent;
	}

	return nextIt;
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::Iter hIntervalMap<Key, Val>::findByRank(size_t r)
{ 
	return _root->findByRankCallback(r); 
}

template <typename Key, typename Val>
bool hIntervalMap<Key, Val>::check(const KeyTy& k, hEnum fdTy)
{
	if (!size())
		return false;

	return _root->checkCallback(k, fdTy);
}

template <typename Key, typename Val>
size_t hIntervalMap<Key, Val>::find(hList<Iter>& fdLst, const KeyTy& k, hEnum fdTy)
{
	return _root->findCallback(fdLst, k, fdTy);
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::Iter hIntervalMap<Key, Val>::begin()
{
	return Iter(this, _begNd, _begValNd);
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::CIter hIntervalMap<Key, Val>::begin() const
{
	return CIter(this, _begNd, _begValNd);
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::Iter hIntervalMap<Key, Val>::end()
{
	return Iter(this, NodeTy::_pNil, NULL);
}

template <typename Key, typename Val>
hIntervalMap<Key, Val>::CIter hIntervalMap<Key, Val>::end() const
{
	return CIter(this, NodeTy::_pNil, NULL);
}

template <typename Key, typename Val>
void hIntervalMap<Key, Val>::clear()
{
	if (_root != NodeTy::_pNil)
	{
		delete _root;
		_root = new hIntervalMapNode<Key, Val>(this);
	}

	_begNd = NodeTy::_pNil;
	_begValNd = NULL;
}

template <typename Key, typename Val>
std::ostream& hIntervalMap<Key, Val>::fillDebug(std::ostream& os) const
{
	return _root->fillDebugCallback(os);
}
